﻿/**************************************************************
 * Copyright www.eastmoney.com. All rights reserved.
 * 
 * Author: gt1987(guitao@eastmoney.com) 
 * Create Date: 2021/3/16 10:02:06
 * Description: 
 *          
 * Revision History:
 *      Date         Author               Description
 *              
***************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Collection.Sample
{
    /// <summary>
    /// 表达式树 sample
    /// </summary>
    public class ExpressionSample
    {
        public void Initialize_Sample()
        {
            //C# 编译器只能从表达式 lambda （或单行 lambda）生成表达式树。 
            Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
            Func<int, bool> func1 = n => n < 0;
            Expression<Func<int, bool>> funcExpression1 = n => n < 0;
            //Expression<Func<int, bool>> funcExpression1 = Expression<Func<int, bool>>.

            //API创建
            ParameterExpression pExpression = Expression.Parameter(typeof(int));
            ConstantExpression cExpression = Expression.Constant(0);
            BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression);
            Expression<Func<int, bool>> funcExpression2 = Expression.Lambda<Func<int, bool>>(bExpression, pExpression);
        }

        public void Analysis_Sample()
        {
            Expression<Func<int, bool>> funcExpression = num => num == 0;
            ParameterExpression pExpression = funcExpression.Parameters[0];
            BinaryExpression bExpression = funcExpression.Body as BinaryExpression;

            Console.WriteLine($"analysis expression:{pExpression.Name}=>{bExpression.Left} {bExpression.NodeType} {bExpression.Right}");
        }

        public void Compile_Sample()
        {
            //编译成可执行委托。
            //执行这些表达式树，需要调用 Compile 方法来创建一个可执行委托，然后调用该委托
            Expression<Func<int, bool>> funcExpression = num => num == 0;
            var func = funcExpression.Compile();

            Console.WriteLine(func(10));
            Console.WriteLine(funcExpression.Compile()(10));
        }

        public void RegisterDuration_Sample()
        {
            Expression<Func<long, long>> exp = time => (long)(DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime().AddSeconds(time)).TotalDays;
            var result = exp.Compile()(long.Parse("1129164525"));

            var slot = GetSlotByKey("h:userbadge:level:1235014041936486BD020");
            Console.WriteLine($"{slot}");
        }

        private int GetSlotByKey(string key)
        {
            int h = 0;
            for (int i = 0; i < key.Length; i++)
            {
                h = 33 * h + (int)key[i];
            }
            return Math.Abs(h) % 16384;
        }

        public void Update_Sample()
        {
            Expression<Func<int, bool>> funcExpression = num => num == 0;

            var visitor = new NotEqualExpressionVisitor();
            var expression = visitor.Visit(funcExpression);

            Console.WriteLine($"update:{expression}");
        }
        class NotEqualExpressionVisitor : ExpressionVisitor
        {
            public Expression Visit(BinaryExpression node)
            {
                return VisitBinary(node);
            }

            protected override Expression VisitBinary(BinaryExpression node)
            {
                return node.NodeType == ExpressionType.Equal
                   ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式：用 != 代替 ==
                   : base.VisitBinary(node);
            }
        }
    }
}
